/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package analisadorlexico;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Sandoval Fiho
 */
public class automato {

    private int estadoAtual;
    private int estadoInicial;
    private int transicoes[][];
    private Hashtable<Integer, String> tabelaStatus; // Tabela Status 
    private LinkedList<Token> listaAceitacao; // lista de estados de aceitacao
    private LinkedList<Token> listaErro;   // lista de estados de erro
    private LinkedList<Integer> estadosConsome; // lista de estados que consomem
    //  private String textoLido;

    public int getEstadoAtual() {
        return estadoAtual;
    }

    public automato(int estadoAtual, int estadoInicial, int[][] transicoes, Hashtable<Integer, String> tabelaStatus, LinkedList<Token> listaAceitacao, LinkedList<Token> listaErro, LinkedList<Integer> estadosConsome) {
        this.estadoAtual = estadoAtual;
        this.estadoInicial = estadoInicial;
        this.transicoes = transicoes;
        this.tabelaStatus = tabelaStatus;
        this.listaAceitacao = listaAceitacao;
        this.listaErro = listaErro;
        this.estadosConsome = estadosConsome;
    }

    public int getEstadoInicial() {
        return estadoInicial;
    }

    public void setEstadoInicial(int estadoInicial) {
        this.estadoInicial = estadoInicial;
    }

    public void setEstadoAtual(int estadoAtual, int ASC) {
        System.out.println("Atual:" + estadoAtual);
        this.estadoAtual = this.transicoes[estadoAtual][ASC];
        System.out.println("Pos:" + estadoAtual);
    }

    public Hashtable<Integer, String> getTabelaStatus() {
        return tabelaStatus;
    }

    public void setTabelaStatus(Hashtable<Integer, String> tabelaStatus) {
        this.tabelaStatus = tabelaStatus;
    }

    public LinkedList<Integer> getEstadosConsome() {
        return estadosConsome;
    }

    public void setEstadosConsome(LinkedList<Integer> estadosConsome) {
        this.estadosConsome = estadosConsome;
    }

    public LinkedList<Token> getListaAceitacao() {
        return listaAceitacao;
    }

    public void setListaAceitacao(LinkedList<Token> listaAceitacao) {
        this.listaAceitacao = listaAceitacao;
    }

    public LinkedList<Token> getListaErro() {
        return listaErro;
    }

    public void setListaErro(LinkedList<Token> listaErro) {
        this.listaErro = listaErro;
    }

    public int[][] getTransicoes() {
        return transicoes;
    }

    public automato(int[][] transicoes, int[] estadoFinal) {
        this.transicoes = transicoes;

    }

    public void setTransicoes(int[][] transicoes) {
        this.transicoes = transicoes;
    }

    public LinkedList<Integer> carregaConsome() {   // Quando chegar aqui incrementa uma posicao
        this.estadosConsome = new LinkedList<>();
        estadosConsome.add(53);
        estadosConsome.add(54);
        estadosConsome.add(55);
        estadosConsome.add(57);
        estadosConsome.add(58);
        estadosConsome.add(60);
        estadosConsome.add(61);
        estadosConsome.add(76);
        return estadosConsome;

    }

    public Hashtable<Integer, String> carregaHash() {   // cadastro da Hash de estados
        this.tabelaStatus = new Hashtable<Integer, String>();
// ACEITACOES        ;
// ACEITACOES        
        this.tabelaStatus.put(50, "Identificador");
        this.tabelaStatus.put(51, "Numero real");
        this.tabelaStatus.put(52, "Numero");
        this.tabelaStatus.put(53, "String");
        this.tabelaStatus.put(54, "Caracter");
        this.tabelaStatus.put(55, "Comentario");
        this.tabelaStatus.put(56, "Operador aritmetico");
        this.tabelaStatus.put(57, "Operador aritmetico");
        this.tabelaStatus.put(58, "Operador lógico");
        this.tabelaStatus.put(59, "Operador lógico");
        this.tabelaStatus.put(60, "Operador relacional");
        this.tabelaStatus.put(61, "Delimitadores");
        this.tabelaStatus.put(62, "Fim de arquivo");
        this.tabelaStatus.put(63, "Operador de atribuicao");
        this.tabelaStatus.put(64, "Operador relacional");
        /*
         50=aceitação identificador
         51=aceitação número real
         52=aceitação número
         53=aceitação string
         54=aceitação caracter
         55=aceitação comentario
         56=aceitação operador aritmetico
         57=aceitação operador aritmetico consome
         58=aceitação operador lógico consome
         59=aceitação operador lógico
         60=aceitação operador relacional consome
         61=aceitação delimitadores
         62=aceitação fim de arquivo
         63=aceitação operador de atibuição
         64=aceitação operador relacional
         */


// ERROS
        this.tabelaStatus.put(70, "Erro na formação do identificador");
        this.tabelaStatus.put(71, "Erro na formação do numero");
        this.tabelaStatus.put(72, "Erro na formação de string");
        this.tabelaStatus.put(73, "Erro na formação de caracter");
        this.tabelaStatus.put(74, "Erro na formação de comentario");
        this.tabelaStatus.put(75, "Erro na formação de operadores lógicos");
        this.tabelaStatus.put(76, "Caracter invalido");
        this.tabelaStatus.put(77, "Operador relacional mal formado");
        /*
         70=Erro na formação do identificador
         71=Erro na formação do numero
         72=Erro na formação de string
         73=Erro na formação de caracter
         74=Erro na formação de comentario
         75=Erro na formação de operadores lógicos
         76=caracter invalido
         77=operador relacional mal formado
         * /*        

         */// System.out.println("TESTE: " + this.tabelaStatus.containsKey(50));
        return this.tabelaStatus;

    }

    public boolean verificaConsome(int estado) {  // verifica se consome
        return getEstadosConsome().contains(estado);
    }

    public boolean verificaEstado(int estado) {

        //    System.out.println("State"+ estado);
        return this.tabelaStatus.containsKey(estado); // verifica se esta na lista de estado de erro ou final

    }

    public boolean palavraReservada(String palavraTeste) { // Método que verifica se é palavra reservad
        String teste = palavraTeste.trim();
        String ListaPalavrasReservadas[] = {"program", "var", "const", "register", "type", "function", "return", "void", "main", "if", "then", "else", "while", "for", "read", "write", "integer", "real", "boolean", "char", "string", "true", "false"};
        int i;
        for (i = 0; i < ListaPalavrasReservadas.length; i++) {

            if (ListaPalavrasReservadas[i].equals(teste)) {

                System.out.println("teste " + ListaPalavrasReservadas[i]);

                return true;

            }

        }
        return false;
    }

    public void verificar(String aux, int linha) {
        if (this.transicoes[this.getEstadoAtual()][0] <= 64) {
            System.out.println("cert:" + aux);
            System.out.println("cert:" + this.palavraReservada(aux));
            if (this.palavraReservada(aux)) {
                this.getListaAceitacao().add(new Token(aux.trim(), "Palavra reservada", linha));
            } else {
                this.getListaAceitacao().add(new Token(aux.trim(), (String) getTabelaStatus().get(transicoes[estadoAtual][0]), linha));
            }
        } else {

            this.getListaErro().add(new Token(aux.trim(), (String) getTabelaStatus().get(transicoes[estadoAtual][0]), linha));
        }
        this.estadoAtual = 0;
    }

    public void lerArquivo(String nomeArquivo) throws FileNotFoundException { //método para ler o arquivo
        boolean eof = false;
        Scanner scanner;
        String texto = "";
        String aux = "";
        aux = aux.trim();
        int linha = 0;
        this.estadoInicial = 0;
        scanner = new Scanner(new FileReader(nomeArquivo + ".txt"));
        while (scanner.hasNext()) {
            linha++;
            texto = scanner.nextLine();
            System.out.println("TEXTO: " + texto);
            for (int i = 0; i < texto.length(); i++) // Varre a linha do texto caracter por caracter
            {
                setEstadoAtual(getEstadoAtual(), texto.codePointAt(i)); // Faz a transicao de estado
                System.out.println("Atual: " + this.estadoAtual);



                if (verificaEstado(transicoes[estadoAtual][0])) { // verifica se o estado autal é final ou de erro
                    System.out.println("auxiliar=" + aux);
                    System.out.println("FINAL");

                    System.out.println("ATUAL=" + this.estadoAtual);
                    if (verificaConsome(transicoes[estadoAtual][0])) {
                        aux = aux + texto.toCharArray()[i];
                        System.out.println("AUX=" + aux);
                        System.out.println("ATUAL=" + getEstadoAtual());

                    } else {
                        i--;
                    }
                    verificar(aux, linha);
                    this.estadoAtual = 0;
                    aux = "";
                } else {
                    aux = aux + texto.toCharArray()[i];
                    System.out.println("AUX=" + aux);
                }

            }

            this.setEstadoAtual(getEstadoAtual(), 257);
            if (verificaEstado(transicoes[estadoAtual][0])) {
                System.out.println("CIMENTARIO" + getEstadoAtual());  // verifica se o estado autal é final ou de erro
                verificar(aux, linha);
                this.estadoAtual = 0;
            }
       
            if (this.getEstadoAtual() == 22 || this.getEstadoAtual() == 23) {
            } else {
                aux = "";
            }

        }
        this.setEstadoAtual(getEstadoAtual(), 256);
        System.out.println("fim");
        verificar(aux, linha);
        scanner.close();

    }

    public String exibirLista(LinkedList lista) {
        ListIterator<Token> iterador = lista.listIterator(0);
        String resultado = "";
        String aux = "";
        while (iterador.hasNext()) {

            Token aceito = iterador.next();
            aux = "Lexema: " + aceito.getLexema() + "\n" + "Linha: " + aceito.getLinha() + "\n" + "Tipo: " + aceito.getTipo() + "\n";
            resultado = resultado + aux;
            System.out.println("Lexema" + aceito.getLexema());
            System.out.println("Linha" + aceito.getLinha());
            System.out.println("Tipo" + aceito.getTipo());

        }
        return resultado;

    }

    public int[][] tabela() {   // Método para a leitura da tabela
        int[][] tab = new int[45][258];
        int linha = 0, coluna = 0, valor, i;
        Scanner scanner1, scanner2;

        try {
            scanner1 = new Scanner(new FileReader("tabela.csv"));
            while (scanner1.hasNext() && linha < 45) {
                scanner2 = new Scanner(scanner1.nextLine()).useDelimiter(";");
                while (scanner2.hasNext()) {
                    valor = Integer.parseInt(scanner2.next());
                    if (valor >= 50) {
                        for (i = 0; i < 258; i++) {
                            tab[linha][i] = valor;
                            // System.out.print("M" + linha + "," + i + "(" + valor + ") ");
                        }
                    } else if (coluna == 127) {
                        for (coluna = 127; coluna <= 255; coluna++) {
                            tab[linha][coluna] = valor;
                            //    System.out.print("M" + linha + "," + coluna + "(" + valor + ") ");
                        }
                    } else {
                        tab[linha][coluna] = valor;
                        //System.out.print("M" + linha + "," + coluna + "(" + valor + ") ");
                        coluna++;
                    }
                }
                System.out.println();
                linha++;
                coluna = 0;
            }
            System.out.println();
        } catch (FileNotFoundException ex) {
            Logger.getLogger(automato.class.getName()).log(Level.SEVERE, null, ex);
        }
        return tab;
    }
}
